home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gdevescp.c < prev    next >
C/C++ Source or Header  |  1994-09-21  |  11KB  |  416 lines

  1. /* Copyright (C) 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevescp.c */
  20. /*
  21.  * Epson 'ESC/P 2' language printer driver.
  22.  *
  23.  * This driver uses the ESC/P2 language raster graphics commands with
  24.  * compression. The driver skips vertical white space, provided that
  25.  * the white space is >= 24/band_size (<~ 1.7mm @ 360dpi!) high. There
  26.  * is no attempt to skip horizontal white space, but the compression
  27.  * greatly reduces the significance of this (a nearly blank line would
  28.  * take about 45 bytes). The driver compresses the data one scan line at
  29.  * a time, even though this is not enforced by the hardware. The reason
  30.  * I have done this is that, since the driver skips data outside the
  31.  * margins, we would have to set up a extra pointers to keep track of
  32.  * the data from the previous scan line. Doing this would add extra
  33.  * complexity at a small saving of disk space.
  34.  *
  35.  * These are the only possible optimisations that remain, and would
  36.  * greatly increase the complexity of the driver. At this point, I don't
  37.  * consider them necessary, but I might consider implementing them if
  38.  * enough people encourage me to do so.
  39.  *
  40.  * Richard Brown (rab@tauon.ph.unimelb.edu.au)
  41.  *
  42.  */
  43.  
  44. #include "gdevprn.h"
  45.  
  46. /*
  47.  * Valid values for X_DPI and Y_DPI: 180, 360
  48.  *
  49.  * The value specified at compile time is the default value used if the
  50.  * user does not specify a resolution at runtime.
  51.  */
  52. #ifndef X_DPI
  53. #  define X_DPI 360
  54. #endif
  55.  
  56. #ifndef Y_DPI
  57. #  define Y_DPI 360
  58. #endif
  59.  
  60. /*
  61.  * Margin definitions: Stylus 800 printer driver:
  62.  *
  63.  * The commented margins are from the User's Manual.
  64.  *
  65.  * The values actually used here are more accurate for my printer.
  66.  * The Stylus paper handling is quite sensitive to these settings.
  67.  * If you find that the printer uses an extra page after every real
  68.  * page, you'll need to increase the top and/or bottom margin.
  69.  */
  70.  
  71. #define STYLUS_L_MARGIN 0.13    /*0.12*/
  72. #define STYLUS_B_MARGIN 0.56    /*0.51*/
  73. #define STYLUS_T_MARGIN 0.34    /*0.12*/
  74. #ifdef A4
  75. #   define STYLUS_R_MARGIN 0.18 /*0.15*/
  76. #else
  77. #   define STYLUS_R_MARGIN 0.38
  78. #endif
  79.  
  80. /*
  81.  * Epson AP3250 Margins:
  82.  */
  83.  
  84. #define AP3250_L_MARGIN 0.18
  85. #define AP3250_B_MARGIN 0.51
  86. #define AP3250_T_MARGIN 0.34
  87. #define AP3250_R_MARGIN 0.28  /* US paper */
  88.  
  89. /* The device descriptor */
  90. private dev_proc_print_page(escp2_print_page);
  91.  
  92. /* Stylus 800 device */
  93. gx_device_printer far_data gs_st800_device =
  94.   prn_device(prn_std_procs, "st800",
  95.     DEFAULT_WIDTH_10THS,
  96.     DEFAULT_HEIGHT_10THS,            
  97.     X_DPI, Y_DPI,
  98.     STYLUS_L_MARGIN, STYLUS_B_MARGIN, STYLUS_R_MARGIN, STYLUS_T_MARGIN,
  99.     1, escp2_print_page);
  100.  
  101. /* AP3250 device */
  102. gx_device_printer far_data gs_ap3250_device =
  103.   prn_device(prn_std_procs, "ap3250",
  104.     DEFAULT_WIDTH_10THS,
  105.     DEFAULT_HEIGHT_10THS,            
  106.     X_DPI, Y_DPI,
  107.     AP3250_L_MARGIN, AP3250_B_MARGIN, AP3250_R_MARGIN, AP3250_T_MARGIN,
  108.     1, escp2_print_page);
  109.  
  110. /* ------ Internal routines ------ */
  111.  
  112. /* Send the page to the printer. */
  113. private int
  114. escp2_print_page(gx_device_printer *pdev, FILE *prn_stream)
  115. {    
  116.     int line_size = gdev_prn_raster((gx_device_printer *)pdev);
  117.     int band_size = 24;    /* 1, 8, or 24 */
  118.     int in_size = line_size * band_size;
  119.  
  120.     byte *buf1 = (byte *)gs_malloc(in_size, 1, "escp2_print_page(buf1)");
  121.     byte *buf2 = (byte *)gs_malloc(in_size, 1, "escp2_print_page(buf2)");
  122.     byte *in = buf1;
  123.     byte *out = buf2;
  124.  
  125.     int skip, lnum, top, bottom, left, width;
  126.     int auto_feed = 1;
  127.     int count, i;
  128.  
  129.     /*
  130.     ** Check for valid resolution:
  131.     **
  132.     **    XDPI    YDPI
  133.     **    360    360
  134.     **    360    180
  135.     **    180    180
  136.     */
  137.  
  138.     if( !( (pdev->x_pixels_per_inch == 180 &&
  139.             pdev->y_pixels_per_inch == 180) ||
  140.            (pdev->x_pixels_per_inch == 360 &&
  141.            (pdev->y_pixels_per_inch == 360 ||
  142.             pdev->y_pixels_per_inch == 180) )) )
  143.            return_error(gs_error_rangecheck);
  144.  
  145.     /*
  146.     ** Check buffer allocations:
  147.     */
  148.  
  149.     if ( buf1 == 0 || buf2 == 0 )
  150.     {    if ( buf1 ) 
  151.           gs_free((char *)buf1, in_size, 1, "escp2_print_page(buf1)");
  152.         if ( buf2 ) 
  153.           gs_free((char *)buf2, in_size, 1, "escp2_print_page(buf2)");
  154.         return_error(gs_error_VMerror);
  155.     }
  156.  
  157.     /*
  158.     ** Reset printer, enter graphics mode:
  159.     */
  160.  
  161.     fwrite("\033@\033(G\001\000\001", 1, 8, prn_stream);
  162.  
  163. #ifdef A4
  164.     /*
  165.     ** After reset, the Stylus is set up for US letter paper.
  166.     ** We need to set the page size appropriately for A4 paper.
  167.     ** For some bizarre reason the ESC/P2 language wants the bottom
  168.     ** margin measured from the *top* of the page:
  169.     */
  170.  
  171.     fwrite("\033(U\001\0\n\033(C\002\0t\020\033(c\004\0\0\0t\020",
  172.                                                     1, 22, prn_stream);
  173. #endif
  174.  
  175.     /*
  176.     ** Set the line spacing to match the band height:
  177.     */
  178.  
  179.     if( pdev->y_pixels_per_inch == 360 )
  180.        fwrite("\033(U\001\0\012\033+\030", 1, 9, prn_stream);
  181.     else
  182.        fwrite("\033(U\001\0\024\033+\060", 1, 9, prn_stream);
  183.  
  184.         /*
  185.         ** If the printer has automatic page feeding, then the paper
  186.         ** will already be positioned at the top margin value, so we
  187.         ** start printing the image from there. Similarly, we must not
  188.         ** try to print or even line feed past the bottom margin, since
  189.         ** the printer will automatically load a new page.
  190.         ** Printers without this feature may actually need to be told
  191.         ** to skip past the top margin.
  192.         */
  193.  
  194.         if( auto_feed ) {
  195.            top = dev_t_margin(pdev) * pdev->y_pixels_per_inch;
  196.            bottom = pdev->height - dev_b_margin(pdev) * pdev->y_pixels_per_inch;
  197.         } else {
  198.            top = 0;
  199.            bottom = pdev->height;
  200.         }
  201.  
  202.         /*
  203.         ** Make left margin and width sit on byte boundaries:
  204.         */
  205.  
  206.         left  = ( (int) (dev_l_margin(pdev) * pdev->x_pixels_per_inch) ) >> 3;
  207.  
  208.         width = ((pdev->width - (int)(dev_r_margin(pdev) * pdev->x_pixels_per_inch)) >> 3) - left;
  209.  
  210.     /*
  211.     ** Print the page:
  212.     */
  213.  
  214.     for ( lnum = top, skip = 0 ; lnum < bottom ; )
  215.     {    
  216.         byte *in_data;
  217.         byte *inp;
  218.         byte *in_end;
  219.         byte *outp;
  220.         register byte *p, *q;
  221.         int lcnt;
  222.  
  223.         /*
  224.         ** Check buffer for 0 data. We can't do this mid-band
  225.         */
  226.  
  227.         gdev_prn_get_bits(pdev, lnum, in, &in_data);
  228.         while ( in_data[0] == 0 &&
  229.                 !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1) &&
  230.                 lnum < bottom )
  231.             {    
  232.             lnum++;
  233.             skip++;
  234.             gdev_prn_get_bits(pdev, lnum, in, &in_data);
  235.         }
  236.  
  237.         if(lnum == bottom ) break;    /* finished with this page */
  238.  
  239.         /*
  240.         ** Skip blank lines if we need to:
  241.         */
  242.  
  243.         if( skip ) {
  244.            fwrite("\033(v\002\000", 1, 5, prn_stream);
  245.            fputc(skip & 0xff, prn_stream);
  246.            fputc(skip >> 8,   prn_stream);
  247.            skip = 0;
  248.         }
  249.  
  250.         lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
  251.  
  252.         /*
  253.         ** Check to see if we don't have enough data to fill an entire
  254.         ** band. Padding here seems to work (the printer doesn't jump
  255.         ** to the next (blank) page), although the ideal behaviour
  256.         ** would probably be to reduce the band height.
  257.         **
  258.         ** Pad with nulls:
  259.         */
  260.  
  261.         if( lcnt < band_size )
  262.            memset(in + lcnt * line_size, 0, in_size - lcnt * line_size);
  263.  
  264.         /*
  265.         ** Now we have a band of data: try to compress it:
  266.         */
  267.  
  268.         for( outp = out, i = 0 ; i < band_size ; i++ ) {
  269.  
  270.            /*
  271.            ** Take margins into account:
  272.            */
  273.  
  274.            inp = in + i * line_size + left;
  275.            in_end = inp + width;
  276.  
  277.            /*
  278.            ** walk through input buffer, looking for repeated data:
  279.            ** Since we need more than 2 repeats to make the compression
  280.            ** worth it, we can compare pairs, since it doesn't matter if we
  281.            **
  282.            */
  283.  
  284.            for( p = inp, q = inp + 1 ; q < in_end ; ) {
  285.  
  286.                if( *p != *q ) {
  287.  
  288.                   p += 2;
  289.                   q += 2;
  290.  
  291.                } else {
  292.  
  293.                   /*
  294.                   ** Check behind us, just in case:
  295.                   */
  296.  
  297.                   if( p > inp && *p == *(p-1) )
  298.                      p--;
  299.  
  300.                /*
  301.                ** walk forward, looking for matches:
  302.                */
  303.  
  304.                for( q++ ; *q == *p && q < in_end ; q++ ) {
  305.                   if( (q-p) >= 128 ) {
  306.                      if( p > inp ) {
  307.                         count = p - inp;
  308.                         while( count > 128 ) {
  309.                        *outp++ = '\177';
  310.                        memcpy(outp, inp, 128);    /* data */
  311.                        inp += 128;
  312.                        outp += 128;
  313.                        count -= 128;
  314.                         }
  315.                         *outp++ = (char) (count - 1); /* count */
  316.                         memcpy(outp, inp, count);    /* data */
  317.                         outp += count;
  318.                      }
  319.                  *outp++ = '\201';    /* Repeat 128 times */
  320.                  *outp++ = *p;
  321.                      p += 128;
  322.                      inp = p;
  323.                   }
  324.                }
  325.  
  326.                if( (q - p) > 2 ) {    /* output this sequence */
  327.                   if( p > inp ) {
  328.                  count = p - inp;
  329.                  while( count > 128 ) {
  330.                     *outp++ = '\177';
  331.                     memcpy(outp, inp, 128);    /* data */
  332.                     inp += 128;
  333.                     outp += 128;
  334.                     count -= 128;
  335.                  }
  336.                  *outp++ = (char) (count - 1);    /* byte count */
  337.                  memcpy(outp, inp, count);    /* data */
  338.                  outp += count;
  339.                   }
  340.                   count = q - p;
  341.                   *outp++ = (char) (256 - count + 1);
  342.                   *outp++ = *p;
  343.                   p += count;
  344.                   inp = p;
  345.                } else    /* add to non-repeating data list */
  346.                   p = q;
  347.                if( q < in_end )
  348.                   q++;
  349.                }
  350.            }
  351.  
  352.            /*
  353.            ** copy remaining part of line:
  354.            */
  355.  
  356.            if( inp < in_end ) {
  357.  
  358.               count = in_end - inp;
  359.  
  360.               /*
  361.               ** If we've had a long run of varying data followed by a
  362.               ** sequence of repeated data and then hit the end of line,
  363.               ** it's possible to get data counts > 128.
  364.               */
  365.  
  366.               while( count > 128 ) {
  367.             *outp++ = '\177';
  368.             memcpy(outp, inp, 128);    /* data */
  369.             inp += 128;
  370.             outp += 128;
  371.             count -= 128;
  372.               }
  373.  
  374.               *outp++ = (char) (count - 1);    /* byte count */
  375.               memcpy(outp, inp, count);    /* data */
  376.               outp += count;
  377.            }
  378.         }
  379.  
  380.         /*
  381.         ** Output data:
  382.         */
  383.  
  384.             fwrite("\033.\001", 1, 3, prn_stream);
  385.  
  386.             if(pdev->y_pixels_per_inch == 360)
  387.                fputc('\012', prn_stream);
  388.         else
  389.                fputc('\024', prn_stream);
  390.  
  391.             if(pdev->x_pixels_per_inch == 360)
  392.                fputc('\012', prn_stream);
  393.         else
  394.                fputc('\024', prn_stream);
  395.  
  396.         fputc(band_size, prn_stream);
  397.  
  398.             fputc((width << 3) & 0xff, prn_stream);
  399.         fputc( width >> 5,         prn_stream);
  400.  
  401.             fwrite(out, 1, (outp - out), prn_stream);
  402.  
  403.             fwrite("\r\n", 1, 2, prn_stream);
  404.         lnum += band_size;
  405.     }
  406.  
  407.     /* Eject the page and reinitialize the printer */
  408.  
  409.     fputs("\f\033@", prn_stream);
  410.     fflush(prn_stream);
  411.  
  412.     gs_free((char *)buf2, in_size, 1, "escp2_print_page(buf2)");
  413.     gs_free((char *)buf1, in_size, 1, "escp2_print_page(buf1)");
  414.     return 0;
  415. }
  416.